class Compiler {
  constructor(el, vm) {
    this.$vm = vm;
    this.el = document.querySelector(el);
    this.compile(this.el);
  }
  compile(node) {
    let nodes = node.childNodes;
    Array.from(nodes).forEach(node => {
      //判断节点类型
      if (this.isElement(node)) {
        //是元素标签
        this.compileElement(node);
      } else if (this.isInter(node)) {
        //是插值文本{{}}
        this.compileText(node);
      }
      this.compile(node);
    });
  }
  isElement(node) {
    return node.nodeType === 1;
  }
  isInter(node) {
    return node.nodeType === 3 && /\{\{(.*)\}\}/.test(node.textContent);
  }
  compileText(node) {
    this.update(node, RegExp.$1, "text");
  }

  compileElement(node) {
    //获取属性
    let nodeAttrs = node.attributes;
    Array.from(nodeAttrs).forEach(attr => {
      const attrName = attr.name;
      const value = attr.value;
      //指令|事件
      if (this.isDirective(attrName)) {
        //截取指令名字
        const dir = attrName.slice(2);
        //执行相应指令的函数
        this[dir] && this[dir](node, value);
      }
    });
  }
  isDirective(attr) {
    return ~attr.indexOf("a-");
  }

  model(node, key) {
    node.value = this.getValueByKey(key);
    node.addEventListener("input", e => {
      this.setValueByKey(key,e.target.value)
    });
  }

  //update函数  负责更新dom，同时创建watcher实例在两者之间产生联系
  update(node, key, dir) {
    //初始运行
    const updaterFn = this[dir + "Updater"];
    updaterFn && updaterFn(node, this.getValueByKey(key));
    
    //修改时的更新埋点
    new Watcher(this.$vm,()=>{
      //回调
      updaterFn && updaterFn(node,this.getValueByKey(key));
    });
    this.getValueByKey(key)//触发依赖收集
    Dep.target = null; //置空
  }

  textUpdater(node, value) {
    node.textContent = value;
  }

  //取出里层值
  getValueByKey(key) {
    let temp = this.$vm;
    if(~key.indexOf(".")){
      key.split(".").forEach(k => {
        temp = temp[k];
      });
    }else{
      temp=temp[key];
    }
    return temp;
  }

  //设置里层值
  //赋值 ["a","b"]==>["a"]["b"]
  //保留最后一个key  选取后直接赋值
  setValueByKey(key, newValue) {
    if(~key.indexOf(".")){
      let arr = key.split(".");
      let temp = this.$vm;
      let lastKey = arr[arr.length - 1];
      arr.forEach(k => {
        if (lastKey != k) {
          temp = temp[k];
        }
      });
      temp[lastKey] = newValue;
    }else{
      this.$vm.$data[key] = newValue
    }
  }
}
